package com.yanfan.xmzS7;

import com.yanfan.iot.service.IDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
@Component
@EnableScheduling
public class S7ConnectorHelper implements ApplicationRunner {

    @Autowired
    private IDeviceService deviceService;
    /**
     * 心跳队列（心跳不能和数据使用同一个队列，否则会导致交叉调用，数据错乱）
     */
    private static final ConcurrentMap<String, S7ReconnectConnector> PLC_HEARTBEAT = new ConcurrentHashMap<>();

    /**
     * 设备队列
     */
    private static final ConcurrentMap<String, S7ReconnectConnector> PLC_DEVICES = new ConcurrentHashMap<>();

    @Override
    public void run(ApplicationArguments args) throws Exception {
        /*List<Device> devices = deviceService.selectDeviceByProductId(25L);
        for (Device device : devices) {
            String privateIp = device.getPrivateIp();
            if (Objects.isNull(privateIp)) {
                continue;
            }

            // 初始化设备心跳队列
            S7ReconnectConnector htConnector = new S7ReconnectConnector(privateIp, S7ReconnectConnector.DEFAULT_DB_NUM, S7ReconnectConnector.DEFAULT_BYTE_OFFSET);
            PLC_HEARTBEAT.put(device.getSerialNumber(), htConnector);
        }
        log.info("=>启动PLC设备监听任务");
        */
    }


    public static ConcurrentMap<String, S7ReconnectConnector> getPlcHeartbeatDevices() {
        return PLC_HEARTBEAT;
    }


    public static ConcurrentMap<String, S7ReconnectConnector> getPlcDevices() {
        return PLC_DEVICES;
    }

    public static synchronized S7ReconnectConnector putPlcHeartbeatDevice(String serialNumber, String ip) {
        PLC_HEARTBEAT.put(serialNumber, new S7ReconnectConnector(ip));
        return PLC_HEARTBEAT.get(serialNumber);
    }

    public static synchronized S7ReconnectConnector putPlcDevice(String serialNumber, String ip) {
        PLC_DEVICES.put(serialNumber, new S7ReconnectConnector(ip));
        return PLC_DEVICES.get(serialNumber);
    }

    public static synchronized void removePlcDevice(String serialNumber) {
        if (PLC_DEVICES.containsKey(serialNumber)) {
            S7ReconnectConnector connector = PLC_DEVICES.get(serialNumber);
            connector.shutdown();
            PLC_DEVICES.remove(serialNumber);
        }
    }

    // 每秒执行心跳
    /*@Scheduled(cron = "0/1 * * * * ?")
    private void heartbeatTask() {
        ConcurrentMap<String, S7ReconnectConnector> htPlc = getPlcHeartbeatDevices();
        if (CollUtil.isNotEmpty(htPlc)) {
            for (String serialNumber : htPlc.keySet()) {
                S7ReconnectConnector connector = htPlc.get(serialNumber);
                // 设备还没有初始化或者初始化失败了
                if (Objects.isNull(connector)) {
                    Device device = deviceService.selectDeviceBySerialNumber(serialNumber);
                    connector = putPlcHeartbeatDevice(serialNumber, device.getPrivateIp());
                }

                // 连接是成功的，尝试执行心跳命令，心跳数据返回验证失败，设为离线，如果心跳失败了，则重新尝试建立连接
                boolean isConnected = (connector.isConnected() || connector.initializeConnection()) && (connector.heartbeat() || connector.initializeConnection());

                // 连接还是断开的，判定是否离线
                if (!isConnected) {
                    remoteManager.pushDeviceStatus(-1L, serialNumber, DeviceStatus.OFFLINE);
                    // 重新初始化
                    DeviceStatusBo bo = DeviceStatusBo
                            .builder()
                            .serialNumber(serialNumber)
                            .status(DeviceStatus.OFFLINE)
                            .build();
                    MessageProducer.sendStatusMsg(bo);
                } else {
                    remoteManager.pushDeviceStatus(-1L, serialNumber, DeviceStatus.ONLINE);
                    DeviceStatusBo bo = DeviceStatusBo
                            .builder()
                            .serialNumber(serialNumber)
                            .status(DeviceStatus.ONLINE)
                            .build();
                    MessageProducer.sendStatusMsg(bo);
                }
            }
        }
    }

    // 每秒执行读取设备数据
    @Scheduled(cron = "0/1 * * * * ?")
    private void readDataTask() {
        ConcurrentMap<String, S7ReconnectConnector> devices = getPlcDevices();
        if (CollUtil.isNotEmpty(devices)) {
            for (String serialNumber : devices.keySet()) {
                S7ReconnectConnector connector = devices.get(serialNumber);
                Device device = deviceService.selectDeviceBySerialNumber(serialNumber);
                // 设备还没有初始化或者初始化失败了
                if (Objects.isNull(connector)) {
                    connector = putPlcDevice(serialNumber, device.getPrivateIp());
                }

                // 连接是断开的，重连后还是没连上，跳过
                boolean connected = (connector.isConnected() || connector.initializeConnection()) && (connector.heartbeat() || connector.initializeConnection());
                if (!connected) { continue; }

                // 执行读取数据命令
                StPlcS7Entity entity = connector.readData(StPlcS7Entity.class);
                if (Objects.nonNull(entity) && entity.getWheartBeat() != 0) {
                    DeviceReportBo reportBo = DeviceReportBo
                            .builder()
                            .serverType(ServerType.MQTT)
                            .data(JSON.toJSONString(entity).getBytes(StandardCharsets.UTF_8))
                            .platformDate(DateUtils.getNowDate())
                            .serialNumber(serialNumber)
                            .topicName(topicsUtils.buildTopic(device.getProductId(), serialNumber, TopicType.PROPERTY_POST))
                            .build();
                    MessageProducer.sendPublishMsg(reportBo);
                }
            }
        }
    }*/
}
